package utils

import (
	"compress/flate"
	"compress/gzip"
	"crypto/tls"
	"errors"
	"fmt"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/http/cookiejar"
	"net/url"
	"strconv"
	"strings"
	"time"
)

type HttpService struct {
	HttpClient *http.Client
}

type InitStruct struct {
	Agent string
}

/*
 */
func (s HttpService) Init(is InitStruct) HttpService {
	var proxy *url.URL
	var err error
	if len(is.Agent) > 0 {
		proxy, err = url.Parse(is.Agent)
		if err != nil {
			panic(err)
		}
	}
	rand.Seed(time.Now().Unix())
	s.HttpClient = &http.Client{
		Timeout: 300 * time.Second,
		// 返回301、302重定向时，不会自动发起重定向访问
		CheckRedirect: func(req *http.Request, via []*http.Request) error {
			return http.ErrUseLastResponse
		},
		Transport: &http.Transport{
			TLSClientConfig: &tls.Config{
				// 不校验https证书
				InsecureSkipVerify: true,
			},
			MaxConnsPerHost:     300,
			MaxIdleConns:        150,
			MaxIdleConnsPerHost: 75,
			IdleConnTimeout:     10 * time.Second,
			Proxy:               http.ProxyURL(proxy),
		},
	}
	jar, _ := cookiejar.New(nil)
	s.HttpClient.Jar = jar
	return s

}

func (s HttpService) HttpPostWithRetry(url, body string, header map[string]string, retryTime int) (result []byte, err error) {
	if retryTime < 0 {
		return nil, errors.New("HttpPostWithRetry retryTime is " + strconv.Itoa(retryTime))
	}
	for i := 0; i < retryTime; i++ {
		if result, err = s.HttpPost(url, body, header); err == nil {
			break
		}
	}
	return
}

func (s HttpService) HttpGetWithRetry(url string, header map[string]string, retryTime int) (result []byte, err error) {
	if retryTime < 0 {
		return nil, errors.New("HttpGetWithRetry retryTime is " + strconv.Itoa(retryTime))
	}
	for i := 0; i < retryTime; i++ {
		if result, err = s.HttpGet(url, header); err == nil {
			break
		}
	}
	return
}

func (s HttpService) HttpPost(url, body string, header map[string]string) ([]byte, error) {
	request, _ := http.NewRequest("POST", url, strings.NewReader(body))
	s.HttpRequestHeaderSet(request, header)
	response, err := s.HttpClient.Do(request)
	if err != nil {
		return nil, err
	}
	if response.StatusCode != 200 {
		return nil, fmt.Errorf("ErrorStatusCode %d", response.StatusCode)
	}

	rd := response.Body
	switch response.Header.Get("Content-Encoding") {
	case "gzip":
		reader, err := gzip.NewReader(rd)
		if err != nil {
			return nil, err
		}
		rd = reader
	case "deflate":
		rd = flate.NewReader(rd)
	}

	if strings.Index(response.Header.Get("Content-Type"), "gbk") >= 0 {
		rd = ioutil.NopCloser(transform.NewReader(rd, simplifiedchinese.GBK.NewEncoder()))
		defer rd.Close()
	}

	var buf []byte
	buf, err = ioutil.ReadAll(rd)
	if err != nil {
		return nil, err
	}

	return buf, nil
}

func (s HttpService) HttpGet(url string, header map[string]string) ([]byte, error) {
	request, _ := http.NewRequest("GET", url, nil)
	s.HttpRequestHeaderSet(request, header)
	response, err := s.HttpClient.Do(request)
	if err != nil {
		return nil, err
	}
	if response.StatusCode != 200 {
		return nil, fmt.Errorf("ErrorStatusCode %d", response.StatusCode)
	}

	rd := response.Body
	switch response.Header.Get("Content-Encoding") {
	case "gzip":
		reader, err := gzip.NewReader(rd)
		if nil != err {
			return nil, err
		}
		rd = reader
	case "deflate":
		rd = flate.NewReader(rd)
	}

	if strings.Index(response.Header.Get("Content-Type"), "gbk") >= 0 {
		rd = ioutil.NopCloser(transform.NewReader(rd, simplifiedchinese.GBK.NewEncoder()))
		defer rd.Close()
	}

	var buf []byte
	buf, err = ioutil.ReadAll(rd)
	if err != nil {
		return nil, err
	}

	return buf, nil
}

//Carrier
//RoleDriver.Store

func (s HttpService) HttpRequestHeaderSet(r *http.Request, args map[string]string) {
	for key, v := range args {
		if len(v) > 0 {
			r.Header.Set(key, v)
		}
	}

}

type Response struct {
	Total int64 `json:"total,omitempty"`
}
